home *** CD-ROM | disk | FTP | other *** search
/ Gekikoh Dennoh Club 5 / Gekikoh Dennoh Club Vol. 5 (Japan).7z / Gekikoh Dennoh Club Vol. 5 (Japan) (Track 01).bin / internet / tcppack / tcppackb.lzh / src / samples / ping.c < prev    next >
C/C++ Source or Header  |  1994-08-09  |  11KB  |  533 lines

  1. /*
  2.  * ping.c - ping
  3.  *
  4.  * Copyright (C) 1994 Tomoaki Tada/F.C.T.
  5.  */
  6.  
  7. static char *rcsid = "$Id: ping.c,v 1.7 1994/08/09 04:10:49 Niggle Exp $";
  8.  
  9. /*
  10.  * $Log: ping.c,v $
  11.  * Revision 1.7  1994/08/09  04:10:49  Niggle
  12.  * enable option -n
  13.  * check damaged packet
  14.  *
  15.  * Revision 1.6  1994/08/04  05:02:08  Niggle
  16.  * inetdé¬ÅφÆôé╡é─éóé╚éóÅΩìçé╠ò\Īé≡ò╧ìX
  17.  *
  18.  * Revision 1.5  1994/08/03  01:57:27  Niggle
  19.  * from addressé≡É│é╡é¡ò\Īé╖éΘéµéñé╔ò╧ìX
  20.  *
  21.  * Revision 1.4  1994/07/28  07:49:19  Niggle
  22.  * no response é╠Ä₧é╠ò\Īé≡ò╧ìX
  23.  *
  24.  * Revision 1.3  1994/07/19  05:16:38  Niggle
  25.  * duplicatesé╔æ╬ë₧
  26.  *
  27.  * Revision 1.2  1994/07/19  03:28:21  Niggle
  28.  * cksumé╠ìéæ¼ë╗
  29.  * usageé╠ò\Ī
  30.  * é╗é╠æ╝éóéδéóéδ
  31.  *
  32.  * Revision 1.1  1994/06/23  03:56:12  Niggle
  33.  * Initial revision
  34.  *
  35.  */
  36.  
  37. #include<stdio.h>
  38. #include<stdlib.h>
  39. #include<string.h>
  40. #include<time.h>
  41. #include<signal.h>
  42. #include<limits.h>
  43. #ifdef __human68k__
  44. #undef __DOS_INLINE__
  45. #define __DOS_INLINE__
  46. #include<sys/dos.h>
  47. #endif
  48.  
  49. #include"network.h"
  50. #include"socket.h"
  51. #include"ping.h"
  52.  
  53. static int send_request (int, long, unsigned short, unsigned short, unsigned short);
  54. static int doping (long, long, long, long);
  55. static void ping_recv (void);
  56. static void ping_send (void);
  57. static void handler (int);
  58. static unsigned short eac (long);
  59. static unsigned short cksum (unsigned char *, unsigned short);
  60. static void display_ratio (void);
  61. static volatile void display_usage (void);
  62. static int isnumstr (const unsigned char *);
  63. static void check_data (const unsigned char *, int);
  64.  
  65. static int ping_socket = -1;
  66. static struct ping ping;
  67. static int no_convert_p;
  68.  
  69. static int sending;
  70. static char *hostname, *ipaddr;
  71. struct mib_entry *icmp_mib;
  72.  
  73. /************************************************
  74.  *                        *
  75.  ************************************************/
  76. void
  77. main (int argc, char **argv)
  78. {
  79.   int i, c;
  80.   long target, interval, count, size;
  81.   struct mib_array *top;
  82.  
  83.   top = get_mib_list ();
  84.   if (!top)
  85.     {
  86.       fprintf (stderr, "TCP/IP driveré═ÅφÆôé╡é─éóé▄é╣é±\n");
  87.       return;
  88.     }
  89.  
  90.   for (i = 0; i < 4; i++)
  91.     {
  92.       if (!strcmp (top[i].name, "ICMP"))
  93.     break;
  94.     }
  95.   if (i < 4)
  96.     icmp_mib = top[i].mib;
  97.   else
  98.     icmp_mib = NULL;
  99.  
  100.   count = -1;
  101.   interval = 1;
  102.   opterr = 1;
  103.   size = 56;
  104.   while ((c = getopt (argc, argv, "c:i:n")) != EOF)
  105.     {
  106.       switch (c)
  107.     {
  108.     case 'c':
  109.       if (!isnumstr (optarg))
  110.         display_usage ();
  111.       count = atol (optarg);
  112.       if (count < 1)
  113.         count = 1;
  114.       break;
  115.     case 'i':
  116.       if (!isnumstr (optarg))
  117.         display_usage ();
  118.       interval = atol (optarg);
  119.       if (interval < 1)
  120.         interval = 1;
  121.       break;
  122.     case 'n':
  123.       no_convert_p = 1;
  124.       break;
  125.     case '?':
  126.       break;
  127.     default:
  128.       break;
  129.     }
  130.     }
  131.  
  132.   if (optind < argc)
  133.     {
  134.       char _ipaddr[64];
  135.  
  136.       if (isipaddr (argv[optind]))
  137.     {
  138.       target = a2n_ipaddr (argv[optind]);
  139.       ipaddr = argv[optind];
  140.     }
  141.       else
  142.     {
  143.       struct hostent *h;
  144.       h = gethostbyname (argv[optind]);
  145.       if (h)
  146.         {
  147.           target = *(long *)h->h_addr;
  148.           ipaddr = n2a_ipaddr (target, _ipaddr);
  149.         }
  150.       else
  151.         {
  152.           ipaddr = NULL;
  153.           target = 0;
  154.         }
  155.     }
  156.       hostname = argv[optind];
  157.  
  158.       if (target)
  159.     {
  160.       signal (SIGINT, handler);
  161.       doping (target, size, interval, count);
  162.       signal (SIGINT, SIG_DFL);
  163.     }
  164.       else
  165.     fprintf (stderr, "ping: host name look up failed\n");
  166.     }
  167.   else
  168.     display_usage ();
  169.  
  170.   return;
  171. }
  172.  
  173. /************************************************
  174.  *                        *
  175.  ************************************************/
  176. static void
  177. display_ratio (void)
  178. {
  179.   double sent, res, avg;
  180.   sent = ping.sent;
  181.   if (sending)
  182.     {
  183.       sent -= 1;
  184.       ping.sent -= 1;
  185.     }
  186.   res = ping.responses;
  187.   avg = res / sent * 100;
  188.   avg = 100.0 - avg;
  189.  
  190.   printf ("\n");
  191.   /* display rate */
  192.   printf ("--- %s ping statistics ---\n", hostname);
  193.   if (ping.dup)
  194.     {
  195.       printf ("%d packets transmitted, %d packets received, +%d duplicates, %.2f%% packet loss\n",
  196.           ping.sent, ping.responses, ping.dup, avg);
  197.     }
  198.   else
  199.     {
  200.       printf ("%d packets transmitted, %d packets received, %.2f%% packet loss\n",
  201.           ping.sent, ping.responses, avg);
  202.     }
  203.   if (ping.responses)
  204.     printf ("round-trip min/avg/max = %d/%.2f/%d ms\n",
  205.         ping.mrtt, (double)ping.srtt / res, ping.Mrtt);
  206.   else
  207.     printf ("round-trip min/avg/max = 0/0/0 ms\n");
  208.   fflush (stdout);
  209.   return;
  210. }
  211.  
  212. /************************************************
  213.  *                        *
  214.  ************************************************/
  215. static void
  216. handler (int dummy)
  217. {
  218.   if (ping_socket)
  219.     close_s (ping_socket);
  220.  
  221.   display_ratio ();
  222.   exit (0);
  223. }
  224.  
  225. /************************************************
  226.  *                        *
  227.  ************************************************/
  228. static int
  229. doping (long target, long len, long interval, long count)
  230. {
  231.   int i;
  232.  
  233.   memset ((char *) &ping, 0, sizeof (ping));
  234.   ping_socket = socket (AF_INET, SOCK_RAW, ICMP_PCTL);
  235.   if (ping_socket == -1)
  236.     return 1;
  237.  
  238.   ping.target = target;
  239.  
  240.   ping.mrtt = LONG_MAX;
  241.   ping.Mrtt = LONG_MIN;
  242.   ping.len = len;
  243.   ping.interval = interval *= CLOCKS_PER_SEC;
  244.  
  245.   printf ("PING %s (%s): %d data bytes\n",  hostname, ipaddr, len);
  246.   fflush (stdout);
  247.  
  248.   ping.sent = 0;
  249.   if (count >= 0)
  250.     {
  251.       for (i = 0; i < count; i++)
  252.     {
  253.       clock_t start;
  254.  
  255.       start = clock ();
  256.       sending = 1;
  257.       ping_send ();
  258.  
  259.       while (clock () - start < interval)
  260.         {
  261.           ping_recv ();
  262. #ifdef __human68k__
  263.           /* check ^C */
  264.           if (_dos_keysns ())
  265.         _dos_getchar ();
  266. #endif
  267.         }
  268.       ping.lost = ping.sent - ping.responses;
  269.     }
  270.     }
  271.   else
  272.     {
  273.       for (;;)
  274.     {
  275.       clock_t start;
  276.  
  277.       start = clock ();
  278.       sending = 1;
  279.       ping_send ();
  280.  
  281.       while (clock () - start < interval)
  282.         {
  283.           ping_recv ();
  284. #ifdef __human68k__
  285.           /* check ^C */
  286.           if (_dos_keysns ())
  287.         _dos_getchar ();
  288. #endif
  289.         }
  290.       sending = 0;
  291.       ping.lost = ping.sent - ping.responses;
  292.     }
  293.     }
  294.  
  295.   close_s (ping_socket); ping_socket = -1;
  296.   display_ratio ();
  297.   return 0;
  298. }
  299.  
  300. /************************************************
  301.  *                        *
  302.  ************************************************/
  303. static void
  304. ping_send (void)
  305. {
  306.   send_request (ping_socket, ping.target, ping.sent++, ping_socket, ping.len);
  307. }
  308.  
  309. /************************************************
  310.  *                        *
  311.  ************************************************/
  312. static void
  313. ping_recv (void)
  314. {
  315.   struct icmp icmp;
  316.   long timestamp, rtt;
  317.   struct sockaddr_in from;
  318.   int fromlen;
  319.   int len;
  320.   int dup_p;
  321.   char buff[2048];
  322.   char _hostname[64];
  323.   clock_t now;
  324.  
  325.   now = clock ();
  326.   fromlen = sizeof (from);
  327.  
  328.   if (!socklen (ping_socket, 0))
  329.     return;
  330.  
  331.   len = recvfrom (ping_socket, buff, ping.len + sizeof (struct icmp),
  332.           0, (char *) &from, &fromlen);
  333.   if (len == -1)
  334.     return;
  335.  
  336.   sending = 0;
  337.   memcpy (&icmp, buff, sizeof (struct icmp));
  338.   if (icmp.type != ICMP_ECHO_REPLY || icmp.id != ping_socket)
  339.     return;
  340.  
  341.   dup_p = 0;
  342.   if (ping.sent == ping.responses + 1 + ping.lost)
  343.     ping.responses++;
  344.   else
  345.     {
  346.       dup_p = 1;
  347.       ping.dup++;
  348.     }
  349.  
  350.   /* Get stamp */
  351.   memcpy ((char *)×tamp, buff + sizeof (struct icmp), sizeof (timestamp));
  352.  
  353.   {
  354.     struct hostent *h;
  355.     long from_ip;
  356.  
  357.     from_ip = from.sin_addr.s_addr;
  358.     if (!no_convert_p)
  359.       {
  360.     h = gethostbyaddr ((char *)&from_ip, sizeof (long), AF_INET);
  361.     if (h)
  362.       {
  363.         char *dot;
  364.         strcpy (_hostname, h->h_name);
  365.         dot = strchr (_hostname, '.');
  366.         if (dot)
  367.           {
  368.         if (!strcmp (dot + 1, get_domain_name ()))
  369.           *dot = '\0';
  370.           }
  371.       }
  372.     else
  373.       n2a_ipaddr (from_ip, _hostname);
  374.       }
  375.     else
  376.       n2a_ipaddr (from_ip, _hostname);
  377.   }
  378.  
  379.  
  380.   /* Compute round trip time, update smoothed estimates */
  381.   rtt = (now - timestamp) * (1000 / CLOCKS_PER_SEC);
  382.   printf ("%d bytes from %s: icmp_seq=%d time=%d ms",
  383.       len, _hostname, icmp.seq, rtt);
  384.   if (dup_p)
  385.     printf (" (DUP!)\n");
  386.   else
  387.     printf ("\n");
  388.  
  389.   check_data (buff, len - sizeof (struct icmp));
  390.  
  391.   if (ping.mrtt > rtt)
  392.     ping.mrtt = rtt;
  393.   if (ping.Mrtt < rtt)
  394.     ping.Mrtt = rtt;
  395.  
  396.   ping.srtt += rtt;
  397.  
  398.   fflush (stdout);
  399. }
  400.  
  401. /************************************************
  402.  *                        *
  403.  ************************************************/
  404. static int
  405. send_request (int s, long target, unsigned short seq, unsigned short id, unsigned short len)
  406. {
  407.   struct icmp *icmp;
  408.   struct sockaddr_in to;
  409.   char data[2048];
  410.  
  411.   /* Set optional data field, if any, to all 55's */
  412.   if (len != 0)
  413.     {
  414.       char *p;
  415.       int i;
  416.  
  417.       p = data + sizeof (struct icmp);
  418.       for (i = 0; i < len; i++)
  419.     *p++ = (char)i;
  420.     }
  421.  
  422.   /* Insert timestamp and build ICMP header */
  423.   *(clock_t *)(data + sizeof (struct icmp)) = clock ();
  424.   if (icmp_mib)
  425.     {
  426.       icmp_mib[21].value.integer++;
  427.       icmp_mib[14].value.integer++;
  428.     }
  429.  
  430.   icmp = (struct icmp *)&data;
  431.   icmp->type = ICMP_ECHO;
  432.   icmp->code = 0;
  433.   icmp->cksum = 0;
  434.   icmp->seq = seq;
  435.   icmp->id = id;
  436.  
  437.   icmp->cksum = cksum ((unsigned char *)icmp, sizeof (struct icmp) + ping.len);
  438.  
  439.   to.sin_family = AF_INET;
  440.   to.sin_addr.s_addr = target;
  441.   sendto (ping_socket, data, sizeof (struct icmp) + len, 0, (char *) &to, sizeof (to));
  442.   return 0;
  443. }
  444.  
  445. /************************************************
  446.  *    16bit é┼ 1é╠òΓÉöé╠ÿaé╠îπÄnûû        *
  447.  ************************************************/
  448. static unsigned short
  449. eac (long sum)
  450. {
  451.   unsigned short csum;
  452.  
  453.   while ((csum = sum >> 16) != 0)
  454.     sum = csum + (sum & 0xffff);
  455.  
  456.   return (unsigned short) (sum & 0xffff);
  457. }
  458.  
  459. /************************************************
  460.  *                        *
  461.  ************************************************/
  462. static unsigned short
  463. cksum (unsigned char *_m, unsigned short _len)
  464. {
  465.   long sum;
  466.   int len;
  467.   unsigned short *p;
  468.  
  469.   len = _len >> 1;
  470.   p = (unsigned short *)_m;
  471.   sum = 0;
  472.   while (len-- != 0)
  473.     sum += *p++;
  474.  
  475.   return ~eac (sum) & 0xffff;
  476. }
  477.  
  478. /************************************************
  479.  *                        *
  480.  ************************************************/
  481. static int
  482. isnumstr (const unsigned char *target)
  483. {
  484.   return strspn ((char *)target, "0123456789") == strlen (target);
  485. }
  486.  
  487. /************************************************
  488.  *                        *
  489.  ************************************************/
  490. static volatile void
  491. display_usage (void)
  492. {
  493.   printf ("usage: ping [-c count] [-i interval] host\n");
  494.   exit (0);
  495. }
  496.  
  497. /************************************************
  498.  *                        *
  499.  ************************************************/
  500. static void
  501. check_data (const unsigned char *buff, int size)
  502. {
  503.   const unsigned char *p;
  504.   int i, bad;
  505.  
  506.   bad = 0;
  507.   p = buff + sizeof (struct icmp) + sizeof (clock_t);
  508.   for (i = sizeof (clock_t); i < size; i++, p++)
  509.     {
  510.       int c;
  511.  
  512.       c = *p;
  513.       if (c != i)
  514.     {
  515.       printf ("wrong data byte #%d should be 0x%x was 0x%x\n", i, i, c);
  516.       bad++;
  517.     }
  518.     }
  519.   if (bad)
  520.     {
  521.       for (i = 0, p = buff + sizeof (struct icmp); i < size; i++, p++)
  522.     {
  523.       if (!i)
  524.         printf ("\t");
  525.       else if (!(i % 24))
  526.         printf ("\n\t");
  527.  
  528.       printf ("%2.2x ", *p);
  529.     }
  530.       printf ("\n");
  531.     }
  532. }
  533.